using Basket.Api.Data;
using BuildingBlocks.Application;
using BuildingBlocks.Application.Behaviors;
using BuildingBlocks.Infrastructure;
using Microsoft.EntityFrameworkCore;
using Microsoft.OpenApi;
using OpenIddict.Validation.AspNetCore;

namespace Basket.Api;

internal static class DependencyInjection
{
    private static readonly string[] DefaultScopes = ["profile", "email", "roles", "offline_access"];
    private static readonly string[] AllowedOrigins = ["http://localhost:5173", "https://localhost:5173"];

    public static IServiceCollection AddBasketApplication(this IServiceCollection services)
    {
        services.AddApplication(typeof(DependencyInjection).Assembly);
        services.AddMediator(config =>
        {
            config.GenerateTypesAsInternal = true;
            config.Assemblies = [typeof(DependencyInjection).Assembly];
            config.Namespace = "Basket.Api";
            config.PipelineBehaviors =
            [
                typeof(LoggingPipelineBehavior<,>),
                typeof(ValidationPipelineBehavior<,>)
            ];
            config.ServiceLifetime = ServiceLifetime.Scoped;
        });

        return services;
    }

    public static IServiceCollection AddBasketPresentation(this IServiceCollection services)
    {
        services.AddOpenApi();
        services.AddCors(options =>
        {
            options.AddPolicy("SpaCors", policy =>
                policy.WithOrigins(AllowedOrigins)
                    .AllowAnyHeader()
                    .AllowAnyMethod());
        });

        services.AddSwaggerGen(options =>
        {
            options.CustomSchemaIds(id => id.FullName!.Replace('+', '-'));

            var oauth2Scheme = new OpenApiSecurityScheme
            {
                Type = SecuritySchemeType.OAuth2,
                Description = "OAuth2.0 Authorization Code Flow",
                Flows = new OpenApiOAuthFlows
                {
                    AuthorizationCode = new OpenApiOAuthFlow
                    {
                        AuthorizationUrl = new Uri("https://localhost:7051/connect/authorize"),
                        TokenUrl = new Uri("https://localhost:7051/connect/token"),
                        Scopes = new Dictionary<string, string>
                        {
                            { "profile", "Profile information" },
                            { "email", "Email address" },
                            { "roles", "User roles" },
                            { "offline_access", "Refresh token" }
                        }
                    }
                }
            };

            options.AddSecurityDefinition("OAuth2", oauth2Scheme);
            options.AddSecurityRequirement(_ => new OpenApiSecurityRequirement
            {
                {
                    new OpenApiSecuritySchemeReference("OAuth2"),
                    DefaultScopes.ToList()
                }
            });
        });

        services.AddAuthentication(OpenIddictValidationAspNetCoreDefaults.AuthenticationScheme);
        services.AddAuthorization();
        services.AddOpenIddict()
            .AddValidation(o =>
            {
                o.SetIssuer("https://localhost:7051/");
                o.AddAudiences("res_server");

                o.UseIntrospection()
                    .SetClientId("res_server")
                    .SetClientSecret("res_server_secret");

                o.UseAspNetCore();
                o.UseSystemNetHttp();
            });

        return services;
    }

    public static IServiceCollection AddBasketInfrastructure(this IServiceCollection services, IConfiguration configuration)
    {
        services.AddInfrastructure(configuration);
        var connectionString = configuration.GetConnectionString("BasketDb");
        services.AddDbContext<BasketDbContext>(options =>
        {
            options.UseNpgsql(connectionString);
        });
        return services;
    }
}
